package com.black.system.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.black.common.constant.CacheConstants;
import com.black.common.core.domain.entity.SysDictType;
import com.black.common.core.domain.resp.SysDictDataResp;
import com.black.common.exception.ServiceException;
import com.black.common.exception.database.PrimaryException;
import com.black.common.exception.database.RecordNotFoundException;
import com.black.common.utils.MessageUtils;
import com.black.common.utils.SecurityUtils;
import com.black.system.domain.req.system.add.SysDictTypeAddReq;
import com.black.system.domain.req.system.edit.SysDictTypeEditReq;
import com.black.system.domain.req.system.query.SysDictTypeQueryReq;
import com.black.system.domain.resp.system.SysDictTypeResp;
import com.black.system.mapper.SysDictTypeMapper;
import com.black.system.service.SysDictDataService;
import com.black.system.service.SysDictTypeService;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SessionCallback;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author L
 * @description 针对表【sys_dict_type(字典类型表)】的数据库操作Service实现
 * @createDate 2024-08-19 10:07:23
 */
@Service
public class SysDictTypeServiceImpl extends ServiceImpl<SysDictTypeMapper, SysDictType>
        implements SysDictTypeService {

    /**
     * 字典明细业务逻辑
     */
    @Autowired
    private SysDictDataService sysDictDataService;

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 程序启动时自动调用 加载字典缓存数据
     */
    @PostConstruct
    public void init() {
        // 如果缓存为空，则加载字典缓存数据
        String key = CacheConstants.SYS_DICT_KEY + "*";
        Set keys = redisTemplate.keys(key);
        if (keys.isEmpty()) {
            this.loadingDictCache();
        }
    }

    @Override
    public PageInfo<SysDictTypeResp> paginationQuery(SysDictTypeQueryReq req) {
        return PageHelper.startPage(req.getPageNum(), req.getPageSize()).doSelectPageInfo(() -> {
            this.baseMapper.paginationQuery(req);
        });
    }

    /**
     * 加载字典缓存数据
     */
    @Override
    public void loadingDictCache() {
        // 获取所有启用的字典数据
        List<SysDictDataResp> list = this.sysDictDataService.findEnableAll();
        // 分组转换，jdk8新特性
        Map<String, List<SysDictDataResp>> collect = list.stream().collect(Collectors.groupingBy(SysDictDataResp::getDictType));

        collect.forEach((k, v) -> {
            // 缓存到redis
            String key = CacheConstants.SYS_DICT_KEY + k;
            redisTemplate.opsForValue().set(key, v);
        });
    }

    /**
     * 清空字典缓存数据
     */
    @Override
    public void clearDictCache() {
        String key = CacheConstants.SYS_DICT_KEY + "*";
        Set keys = redisTemplate.keys(key);
        this.redisTemplate.delete(keys);
    }

    /**
     * 重置字典缓存数据
     */
    @Override
    public void resetDictCache() {
        this.clearDictCache();
        this.loadingDictCache();
    }

    /**
     * 添加字典类型
     *
     * @param req
     * @return
     */
    @Override
    public boolean add(SysDictTypeAddReq req) {

        // 校验 字典类型是否已存在
        if (this.baseMapper.exists(new LambdaQueryWrapper<SysDictType>().eq(SysDictType::getDictType, req.getDictType()))) {
            throw new ServiceException(MessageUtils.message("sysdicttype.dictType.exists"));
        }
        // 校验 字典名称是否已存在
        if (this.baseMapper.exists(new LambdaQueryWrapper<SysDictType>().eq(SysDictType::getDictName, req.getDictName()))) {
            throw new ServiceException(MessageUtils.message("sysdicttype.dictName.exists"));
        }

        SysDictType newEntity = new SysDictType();
        // 对象拷贝
        BeanUtils.copyProperties(req, newEntity);

        boolean save = this.save(newEntity);
        if (save) {
            //清空缓存
            this.clearDictCache();
        }

        return save;
    }

    /**
     * 编辑字典类型
     *
     * @param req
     * @return
     */
    @Override
    public boolean edit(SysDictTypeEditReq req) {
        // 根据主键查询字典类型
        SysDictType sysDictType = this.getById(req.getDictId());
        if (Objects.isNull(sysDictType)) {
            throw new RecordNotFoundException();
        }

        // 校验 字典类型是否已存在
        if (!req.getDictType().equals(sysDictType.getDictType())) {
            if (this.baseMapper.exists(new LambdaQueryWrapper<SysDictType>().eq(SysDictType::getDictType, req.getDictType()))) {
                throw new ServiceException(MessageUtils.message("sysdicttype.dictType.exists"));
            }
        }
        // 校验 字典名称是否已存在
        if (!req.getDictName().equals(sysDictType.getDictName())) {
            if (this.baseMapper.exists(new LambdaQueryWrapper<SysDictType>().eq(SysDictType::getDictName, req.getDictName()))) {
                throw new ServiceException(MessageUtils.message("sysdicttype.dictName.exists"));
            }
        }

        BeanUtils.copyProperties(req, sysDictType);
        sysDictType.setUpdateBy(SecurityUtils.getUsername());
        boolean res = this.updateById(sysDictType);
        if (res) {
            redisTemplate.opsForValue().set(CacheConstants.SYS_DICT_KEY + req.getDictType(), sysDictType);
        }
        return res;
    }

    /**
     * 根据主键查询字典类型
     *
     * @param id
     * @return
     */
    @Override
    public SysDictTypeResp findById(Long id) {
        if (Objects.isNull(id)) {
            throw new PrimaryException();
        }
        // 根据主键查询
        SysDictType sysDictType = this.getById(id);
        if (Objects.isNull(sysDictType)) {
            throw new RecordNotFoundException();
        }

        // 封装响应对象
        SysDictTypeResp resp = new SysDictTypeResp();
        BeanUtils.copyProperties(sysDictType, resp);
        return resp;
    }

    /**
     * 删除字典类型
     *
     * @param ids
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean deleteById(Long[] ids) {

        final SysDictTypeServiceImpl sysDictTypeService = this;

        if (Objects.isNull(ids) || ids.length == 0) {
            throw new PrimaryException();
        }

        this.redisTemplate.execute(new SessionCallback<Void>() {
            @Override
            public Void execute(RedisOperations operations) throws DataAccessException {
                // 开启事务
                operations.multi();

                // 循环删除
                try {
                    for (Long id : ids) {
                        SysDictType sysDictType = sysDictTypeService.getById(id);
                        if (Objects.nonNull(sysDictType)) {
                            // 删除字典数据
//                              sysDictDataService.remove(new LambdaQueryWrapper<SysDictData>().eq(SysDictData::getDictType, sysDictType.getDictType()));
                            // 删除字典类型
                            sysDictTypeService.removeById(sysDictType);
                            // 删除缓存
                            operations.delete(CacheConstants.SYS_DICT_KEY + sysDictType.getDictType());
                        }
                    }
                    // 提交事务
                    operations.exec();
                } catch (Exception e) {
                    // 回滚事务
                    operations.discard();
                    throw e;
                }
                return null;
            }
        });
        return true;
    }

    /**
     * 导出字典类型
     *
     * @param req
     * @param ids
     * @return
     */
    @Override
    public List<SysDictTypeResp> export(SysDictTypeQueryReq req, Long[] ids) {
        List<SysDictTypeResp> dataList;
        // 根据主键导出
        if (Objects.nonNull(ids) && ids.length > 0) {
            dataList = this.baseMapper.exportByIds(ids);
        } else {
            // 按查询条件导出
            dataList = this.baseMapper.paginationQuery(req);
        }
        return dataList;
    }
}




